from jili.core.printlog import print
from xtquant import xtdata
from jili.tool.convert import str2datetime
import datetime
def xttime2datetime(i):
    return datetime.datetime.fromtimestamp(i/1000)
ats2xt_mkcode={
    "SH":"SH",
    "SZ":"SZ",
    # "BJ":"BJSE",
    # "HK":"HK",
    # "SHK":"SHK",
    # "ZHK":"ZHK",
    'CFFEX':"IF",
    'CZCE':"ZF",
    'DCE':"DF",
    'GFEX':"GF",
    'INE':"INE",
    'SHFE' :"SF"
}
xt2ats_mkcode={v: k for k, v in ats2xt_mkcode.items()}
def obj2code(obj,mkcode=None):
    if mkcode is None:
        if "." in obj:
            obj,mkcode=obj.split(".")
            if mkcode in ats2xt_mkcode.keys():
                mkcode=ats2xt_mkcode[mkcode]
        else:
            if obj[0]>"3":
                mkcode="SH"
            else:
                mkcode="SZ"
    else:
        if mkcode in ats2xt_mkcode.keys():
            mkcode = ats2xt_mkcode[mkcode]
    return obj+"."+mkcode
def code2obj(code):
    obj,mkcode=code.split(".")
    if mkcode in xt2ats_mkcode.keys():
        mkcode=xt2ats_mkcode[mkcode]
    return obj,mkcode
class tick_l1():
    def __init__(self):
        self.ticks={}
    def reset(self):
        self.ticks={}
    def xtick2tick0(self,code,tick,call=None):
        timekey = xttime2datetime(tick["time"])
        cum_amount = tick["amount"]
        if tick["pvolume"]>0:
            cum_volume = tick["pvolume"]
        else:
            cum_volume = tick["volume"]*100

        r=self.ticks.get(code)
        if r is None:
            self.ticks[code] = (timekey, cum_amount, cum_volume)
            amount = cum_amount
            volume = cum_volume
        else:
            timekey0, cum_amount0, cum_volume0 = r
            if timekey0 < timekey:
                amount =  cum_amount-cum_amount0
                volume =  cum_volume-cum_volume0
                self.ticks[code] = (timekey, cum_amount, cum_volume)
            else:
                return None
        t = {}
        t["timekey"] = timekey

        t["obj"], t["mkcode"] = code2obj(code)
        t["code"] = t["obj"]+"."+ t["mkcode"]
        t["lastPrice"] = tick["lastPrice"]
        t["amount"] = amount
        t["volume"] = volume
        if cum_volume==0:
            avgPrice=tick["lastPrice"]
        else:
            avgPrice=cum_amount/cum_volume
        t["avgPrice"]=avgPrice
        t["askPrice"] = tick["askPrice"]
        t["bidPrice"] = tick["bidPrice"]
        t["askVol"] = tick["askVol"]
        t["bidVol"] = tick["bidVol"]
        t["high"]=tick["high"]
        t["low"] = tick["low"]
        t["num_trades"] = tick["transactionNum"]
        if call is not None:
            call(t)
        return t
    def xtick2tick2(self,code,tick,call=None):
        timekey = xttime2datetime(tick["time"])
        cum_amount = tick["amount"]
        if tick["pvolume"] > 0:
            cum_volume = tick["pvolume"]
        else:
            cum_volume = tick["volume"] * 100
        r=self.ticks.get(code)
        if r is None:
            self.ticks[code] = (timekey, cum_amount, cum_volume)
            amount = cum_amount
            volume = cum_volume
        else:
            timekey0, cum_amount0, cum_volume0 = r
            if timekey0 < timekey:
                amount =  cum_amount-cum_amount0
                volume =  cum_volume-cum_volume0
                self.ticks[code] = (timekey, cum_amount, cum_volume)
            else:
                return None
        tick["timekey"] = timekey
        tick["obj"], tick["mkcode"] = code2obj(code)
        tick["code"] = tick["obj"] + "." + tick["mkcode"]
        tick["close"] = tick["lastPrice"]
        tick["cumAmount"] = cum_amount
        tick["cumVolume"] = cum_volume
        if cum_volume==0:
            avgPrice=tick["lastPrice"]
        else:
            avgPrice=cum_amount/cum_volume
        tick["avgPrice"]=avgPrice
        tick["amount"] = amount
        tick["volume"] = volume
        tick["num_trades"] = tick["transactionNum"]
        if call is not None:
            call(tick)
        return tick
    def xtick2tick1(self,code,tick,call=None):
        timekey = xttime2datetime(tick["time"])
        cum_amount = tick["amount"]
        if tick["pvolume"] > 0:
            cum_volume = tick["pvolume"]
        else:
            cum_volume = tick["volume"] * 100
        r=self.ticks.get(code)
        if r is None:
            self.ticks[code] = (timekey, cum_amount, cum_volume)
            amount = cum_amount
            volume = cum_volume
        else:
            timekey0, cum_amount0, cum_volume0 = r
            if timekey0 < timekey:
                amount =  cum_amount-cum_amount0
                volume =  cum_volume-cum_volume0
                self.ticks[code] = (timekey, cum_amount, cum_volume)
            else:
                return None
        tick["timekey"] = timekey
        tick["obj"], tick["mkcode"] = code2obj(code)
        tick["code"] = tick["obj"] + "." + tick["mkcode"]
        tick["close"] = tick["lastPrice"]
        tick["cumAmount"] = cum_amount
        tick["cumVolume"] = cum_volume
        tick["amount"] = amount
        tick["volume"] = volume
        if cum_volume==0:
            avgPrice=tick["lastPrice"]
        else:
            avgPrice=cum_amount/cum_volume
        tick["avgPrice"]=avgPrice
        tick["num_trades"] = tick["transactionNum"]
        if call is not None:
            call(tick)
        return tick
periods={#60s, 300s, 900s, 1800s, 3600s
    "tick": "tick",
    "k1m":"1m",
    "k5m":"5m",
    "k15m":"15m",
    "k30m":"30m",
    "k60m":"1h",
    "k120m":"2h",
    "k1d":"1d"
}
periods1={v: k for k, v in periods.items()}
ats2xt_fqtype={
    "qfq":"front_ratio",
    "hfq":"back_ratio",
    "bfq":"none"
}
def ats2xt_period(period):
    if period in periods.keys():
        return periods[period]
    else:
        return period[1:]

class pricetool():
    def __init__(self,ip = '', port = None):
        self.subscribe_quote_ids=[]
        self.subscribe_whole_quote_ids=[]
        self.obj_infos={}
        self.tool = xtdata
        try:
            xtdata.connect(ip=ip,port=port)
        except Exception as e:
            print(e)
            print("请启动QMT程序后再启动策略")

    def get_objinfo(self,obj):
        # obj=tool.obj2xtcode(obj)
        if obj not in self.obj_infos.keys():
            code=obj2code(obj)
            self.obj_infos[obj] = xtdata.get_instrument_detail(code)
        return self.obj_infos[obj]
    def get_tradeday(self,count=1,end_date=None):
        if end_date is None:
            now = datetime.datetime.now()
            today = datetime.datetime(now.year, now.month, now.day)
        else:
            if isinstance(end_date,str):
                today=str2datetime(end_date)
            else:
                today=end_date
        dt = xtdata.get_trading_dates(market="SH", count=count, end_time=today.strftime("%Y%m%d"))
        tdays = []
        for i in dt:
            tdays.append(xttime2datetime(i))
        return tdays
    def istradeday(self):
        td=self.get_tradeday()
        now = datetime.datetime.now()
        today = datetime.datetime(now.year, now.month, now.day)
        if today==td[0]:
            return True
        else:
            return False
    def subscribe_whole_quote(self,code=["ZH","SH"], callback=None):
        if not isinstance(code,list):
            code=[code]
        r=xtdata.subscribe_whole_quote(code_list=code, callback=callback)
        self.subscribe_whole_quote_ids.append(r)
        return r
    def subscribe(self,obj, period='k30m', callback=None):
        if isinstance(obj, str):
            codes = [obj2code(obj)]
        else:
            codes = []
            for i in obj:
                codes.append(obj2code(i))
        # period0 = ats2xt_period(period)
        r=self.subscribe_quote(codes, period=period, callback=callback)
        return r
    def subscribe_quote(self,code, period='k1d', start_time='', end_time='', count=0, callback=None):
        period0 = ats2xt_period(period)
        # period: str, K线周期类型
        # 可选范围： 'tick': 分笔线
        # '1d': 日线
        # '1m': 分钟线
        # '3m': 三分钟线
        # '5m': 5
        # 分钟线
        # '15m': 15
        # 分钟线
        # '30m': 30
        # 分钟线
        # '1h': 小时线
        # '1w': 周线
        # '1mon': 月线
        # '1q': 季线
        # '1hy': 半年线
        # '1y': 年线
        r=xtdata.subscribe_quote(stock_code=code, period=period0, start_time=start_time, end_time=end_time, count=count, callback=callback)
        print("subscribe_quote",r,code,period,period0,start_time,end_time,count,callback)
        self.subscribe_quote_ids.append(r)
        return r
    def get_today_bar(self,obj,period="k1d"):
        bars=self.get_prebars(obj,count=1,period=period,fqtype="bfq")
        if bars:
            return bars[-1]
        else:
            return {}
    def get_prebars(self,obj,count=100,period="k1d",fqtype="qfq",start_time='',end_time=''):
        obj=obj2code(obj)
        fqtype0 = ats2xt_fqtype.get(fqtype,"none")
        period0=ats2xt_period(period)

        """
        none 不复权
        front 前复权
        back 后复权
        front_ratio 等比前复权
        back_ratio 等比后复权
        """
        """
        tick - 分笔数据
        1m - 1分钟线
        5m - 5分钟线
        15m - 15分钟线
        30m - 30分钟线
        1h - 1小时线
        1d - 日线
        1w - 周线
        1mon - 月线
        1q - 季度线
        1hy - 半年线
        1y - 年线
        """
        print("price_xt get_prebars", obj, count, period,period0, fqtype,fqtype0, start_time, end_time)
        xtdata.download_history_data(stock_code=obj, period=period0, start_time=start_time, end_time=end_time, incrementally = None)
        bars=xtdata.get_market_data(stock_list=[obj], period=period0, start_time=start_time, end_time=end_time, count=count, dividend_type=fqtype0, fill_data=True)
        bars0 = {}
        for k, v in bars.items():
            for obj, vv in v.to_dict("index").items():
                for d, vvv in vv.items():
                    if obj not in bars0.keys():
                        bars0[obj] = {}
                    if d not in bars0[obj].keys():
                        bars0[obj][d] = {}
                    bars0[obj][d][k] = vvv
        rst={}
        for obj,v in bars0.items():
            for d,vv in v.items():
                vv["timekey"]=str2datetime(d)
                vv["code"]=obj
                vv["obj"],vv["mkcode"]=code2obj(obj)
            rst[obj]=list(v.values())
        if obj in rst.keys():
            return rst[obj]
        else:
            return []
    def close(self):
        for i in self.subscribe_quote_ids:
            print("unsubscribe_quote",i)
            xtdata.unsubscribe_quote(i)

    def run(self):
        self.tool.run()

if __name__=="__main__":
    from jili.xtlib import tool
    pt=pricetool()
    def on_price(datas):
        for code, t in datas.items():
            timekey = tool.xttime2datetime(t["time"])
            t["timekey"] = timekey
            t["code"]=code
            t["obj"],t["mkcode"]=tool.xtcode2obj(code)
            print("on_calc_price",code,timekey,t)


    pt.subscribe_quote("000001.SZ", period="tick", callback=on_price)
    # pt.subscribe_quote("000001.SZ",period="k15m",callback=on_price)
    # pt.subscribe_quote("000001.SZ", period="k30m", callback=on_price)
    # pt.subscribe_quote("000001.SZ", period="k60m", callback=on_price)
    # pt.subscribe_quote("000001.SZ", period="k1d", callback=on_price)
    pt.tool.run()